using System;
using System.Collections;
using Server.Commands;

namespace Server.Items
{
    public class StealableArtifactsSpawner : Item
    {
        public class StealableEntry
        {
            private readonly Map m_Map;
            private readonly Point3D m_Location;
            private readonly int m_MinDelay;
            private readonly int m_MaxDelay;
            private readonly Type m_Type;
            private readonly int m_Hue;

            public Map Map
            {
                get
                {
                    return this.m_Map;
                }
            }
            public Point3D Location
            {
                get
                {
                    return this.m_Location;
                }
            }
            public int MinDelay
            {
                get
                {
                    return this.m_MinDelay;
                }
            }
            public int MaxDelay
            {
                get
                {
                    return this.m_MaxDelay;
                }
            }
            public Type Type
            {
                get
                {
                    return this.m_Type;
                }
            }
            public int Hue
            {
                get
                {
                    return this.m_Hue;
                }
            }

            public StealableEntry(Map map, Point3D location, int minDelay, int maxDelay, Type type) : this(map, location, minDelay, maxDelay, type, 0)
            {
            }

            public StealableEntry(Map map, Point3D location, int minDelay, int maxDelay, Type type, int hue)
            {
                this.m_Map = map;
                this.m_Location = location;
                this.m_MinDelay = minDelay;
                this.m_MaxDelay = maxDelay;
                this.m_Type = type;
                this.m_Hue = hue;
            }

            public Item CreateInstance()
            {
                Item item = (Item)Activator.CreateInstance(this.m_Type);

                if (this.m_Hue > 0)
                    item.Hue = this.m_Hue;

                item.Movable = false;
                item.MoveToWorld(this.Location, this.Map);

                return item;
            }
        }

        private static readonly StealableEntry[] m_Entries = new StealableEntry[]
        {
            // Doom - Artifact rarity 1
            new StealableEntry(Map.Malas, new Point3D(317, 56, -1), 72, 108, typeof(RockArtifact)),
            new StealableEntry(Map.Malas, new Point3D(360, 31, 8), 72, 108, typeof(SkullCandleArtifact)),
            new StealableEntry(Map.Malas, new Point3D(369, 372, -1), 72, 108, typeof(BottleArtifact)),
            new StealableEntry(Map.Malas, new Point3D(378, 372, 0), 72, 108, typeof(DamagedBooksArtifact)),
            // Doom - Artifact rarity 2
            new StealableEntry(Map.Malas, new Point3D(432, 16, -1), 144, 216, typeof(StretchedHideArtifact)),
            new StealableEntry(Map.Malas, new Point3D(489, 9, 0), 144, 216, typeof(BrazierArtifact)),
            // Doom - Artifact rarity 3
            new StealableEntry(Map.Malas, new Point3D(471, 96, -1), 288, 432, typeof(LampPostArtifact), GetLampPostHue()),
            new StealableEntry(Map.Malas, new Point3D(421, 198, 2), 288, 432, typeof(BooksNorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(431, 189, -1), 288, 432, typeof(BooksWestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(435, 196, -1), 288, 432, typeof(BooksFaceDownArtifact)),
            // Doom - Artifact rarity 5
            new StealableEntry(Map.Malas, new Point3D(447, 9, 8), 1152, 1728, typeof(StuddedLeggingsArtifact)),
            new StealableEntry(Map.Malas, new Point3D(423, 28, 0), 1152, 1728, typeof(EggCaseArtifact)),
            new StealableEntry(Map.Malas, new Point3D(347, 44, 4), 1152, 1728, typeof(SkinnedGoatArtifact)),
            new StealableEntry(Map.Malas, new Point3D(497, 57, -1), 1152, 1728, typeof(GruesomeStandardArtifact)),
            new StealableEntry(Map.Malas, new Point3D(381, 375, 11), 1152, 1728, typeof(BloodyWaterArtifact)),
            new StealableEntry(Map.Malas, new Point3D(489, 369, 2), 1152, 1728, typeof(TarotCardsArtifact)),
            new StealableEntry(Map.Malas, new Point3D(497, 369, 5), 1152, 1728, typeof(BackpackArtifact)),
            // Doom - Artifact rarity 7
            new StealableEntry(Map.Malas, new Point3D(475, 23, 4), 4608, 6912, typeof(StuddedTunicArtifact)),
            new StealableEntry(Map.Malas, new Point3D(423, 28, 0), 4608, 6912, typeof(CocoonArtifact)),
            // Doom - Artifact rarity 8
            new StealableEntry(Map.Malas, new Point3D(354, 36, -1), 9216, 13824, typeof(SkinnedDeerArtifact)),
            // Doom - Artifact rarity 9
            new StealableEntry(Map.Malas, new Point3D(433, 11, -1), 18432, 27648, typeof(SaddleArtifact)),
            new StealableEntry(Map.Malas, new Point3D(403, 31, 4), 18432, 27648, typeof(LeatherTunicArtifact)),
            // Doom - Artifact rarity 10
            new StealableEntry(Map.Malas, new Point3D(257, 70, -2), 36864, 55296, typeof(ZyronicClaw)),
            new StealableEntry(Map.Malas, new Point3D(354, 176, 7), 36864, 55296, typeof(TitansHammer)),
            new StealableEntry(Map.Malas, new Point3D(369, 389, -1), 36864, 55296, typeof(BladeOfTheRighteous)),
            new StealableEntry(Map.Malas, new Point3D(467, 92, 4), 36864, 55296, typeof(InquisitorsResolution)),
            // Doom - Artifact rarity 12
            new StealableEntry(Map.Malas, new Point3D(487, 364, -1), 147456, 221184, typeof(RuinedPaintingArtifact)),

            // Yomotsu Mines - Artifact rarity 1
            new StealableEntry(Map.Malas, new Point3D(18, 110, -1), 72, 108, typeof(Basket1Artifact)),
            new StealableEntry(Map.Malas, new Point3D(66, 114, -1), 72, 108, typeof(Basket2Artifact)),
            // Yomotsu Mines - Artifact rarity 2
            new StealableEntry(Map.Malas, new Point3D(63, 12, 11), 144, 216, typeof(Basket4Artifact)),
            new StealableEntry(Map.Malas, new Point3D(5, 29, -1), 144, 216, typeof(Basket5NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(30, 81, 3), 144, 216, typeof(Basket5WestArtifact)),
            // Yomotsu Mines - Artifact rarity 3
            new StealableEntry(Map.Malas, new Point3D(115, 7, -1), 288, 432, typeof(Urn1Artifact)),
            new StealableEntry(Map.Malas, new Point3D(85, 13, -1), 288, 432, typeof(Urn2Artifact)),
            new StealableEntry(Map.Malas, new Point3D(110, 53, -1), 288, 432, typeof(Sculpture1Artifact)),
            new StealableEntry(Map.Malas, new Point3D(108, 37, -1), 288, 432, typeof(Sculpture2Artifact)),
            new StealableEntry(Map.Malas, new Point3D(121, 14, -1), 288, 432, typeof(TeapotNorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(121, 115, -1), 288, 432, typeof(TeapotWestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(84, 40, -1), 288, 432, typeof(TowerLanternArtifact)),
            // Yomotsu Mines - Artifact rarity 9
            new StealableEntry(Map.Malas, new Point3D(94, 7, -1), 18432, 27648, typeof(ManStatuetteSouthArtifact)),

            // Fan Dancer's Dojo - Artifact rarity 1
            new StealableEntry(Map.Malas, new Point3D(113, 640, -2), 72, 108, typeof(Basket3NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(102, 355, -1), 72, 108, typeof(Basket3WestArtifact)),
            // Fan Dancer's Dojo - Artifact rarity 2
            new StealableEntry(Map.Malas, new Point3D(99, 370, -1), 144, 216, typeof(Basket6Artifact)),
            new StealableEntry(Map.Malas, new Point3D(100, 357, -1), 144, 216, typeof(ZenRock1Artifact)),
            // Fan Dancer's Dojo - Artifact rarity 3
            new StealableEntry(Map.Malas, new Point3D(73, 473, -1), 288, 432, typeof(FanNorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(99, 372, -1), 288, 432, typeof(FanWestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(92, 326, -1), 288, 432, typeof(BowlsVerticalArtifact)),
            new StealableEntry(Map.Malas, new Point3D(97, 470, -1), 288, 432, typeof(ZenRock2Artifact)),
            new StealableEntry(Map.Malas, new Point3D(103, 691, -1), 288, 432, typeof(ZenRock3Artifact)),
            // Fan Dancer's Dojo - Artifact rarity 4
            new StealableEntry(Map.Malas, new Point3D(103, 336, 4), 576, 864, typeof(Painting1NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(59, 381, 4), 576, 864, typeof(Painting1WestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(84, 401, 2), 576, 864, typeof(Painting2NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(59, 392, 2), 576, 864, typeof(Painting2WestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(107, 483, -1), 576, 864, typeof(TripleFanNorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(50, 475, -1), 576, 864, typeof(TripleFanWestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(107, 460, -1), 576, 864, typeof(BowlArtifact)),
            new StealableEntry(Map.Malas, new Point3D(90, 502, -1), 576, 864, typeof(CupsArtifact)),
            new StealableEntry(Map.Malas, new Point3D(107, 688, -1), 576, 864, typeof(BowlsHorizontalArtifact)),
            new StealableEntry(Map.Malas, new Point3D(112, 676, -1), 576, 864, typeof(SakeArtifact)),
            // Fan Dancer's Dojo - Artifact rarity 5
            new StealableEntry(Map.Malas, new Point3D(135, 614, -1), 1152, 1728, typeof(SwordDisplay1NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(50, 482, -1), 1152, 1728, typeof(SwordDisplay1WestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(119, 672, -1), 1152, 1728, typeof(Painting3Artifact)),
            // Fan Dancer's Dojo - Artifact rarity 6
            new StealableEntry(Map.Malas, new Point3D(90, 326, -1), 2304, 3456, typeof(Painting4NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(99, 354, -1), 2304, 3456, typeof(Painting4WestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(179, 652, -1), 2304, 3456, typeof(SwordDisplay2NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(118, 627, -1), 2304, 3456, typeof(SwordDisplay2WestArtifact)),
            // Fan Dancer's Dojo - Artifact rarity 7
            new StealableEntry(Map.Malas, new Point3D(90, 483, -1), 4608, 6912, typeof(FlowersArtifact)),
            // Fan Dancer's Dojo - Artifact rarity 8
            new StealableEntry(Map.Malas, new Point3D(71, 562, -1), 9216, 13824, typeof(DolphinLeftArtifact)),
            new StealableEntry(Map.Malas, new Point3D(102, 677, -1), 9216, 13824, typeof(DolphinRightArtifact)),
            new StealableEntry(Map.Malas, new Point3D(61, 499, 0), 9216, 13824, typeof(SwordDisplay3SouthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(182, 669, -1), 9216, 13824, typeof(SwordDisplay3EastArtifact)),
            new StealableEntry(Map.Malas, new Point3D(162, 647, -1), 9216, 13824, typeof(SwordDisplay4WestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(124, 624, 0), 9216, 13824, typeof(Painting5NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(146, 649, 2), 9216, 13824, typeof(Painting5WestArtifact)),
            // Fan Dancer's Dojo - Artifact rarity 9
            new StealableEntry(Map.Malas, new Point3D(100, 488, -1), 18432, 27648, typeof(SwordDisplay4NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(175, 606, 0), 18432, 27648, typeof(SwordDisplay5NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(157, 608, -1), 18432, 27648, typeof(SwordDisplay5WestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(187, 643, 1), 18432, 27648, typeof(Painting6NorthArtifact)),
            new StealableEntry(Map.Malas, new Point3D(146, 623, 1), 18432, 27648, typeof(Painting6WestArtifact)),
            new StealableEntry(Map.Malas, new Point3D(178, 629, -1), 18432, 27648, typeof(ManStatuetteEastArtifact))
        };

        public static StealableEntry[] Entries
        {
            get
            {
                return m_Entries;
            }
        }

        private static Type[] m_TypesOfEntries = null;
        public static Type[] TypesOfEntires
        {
            get
            {
                if (m_TypesOfEntries == null)
                {
                    m_TypesOfEntries = new Type[m_Entries.Length];

                    for (int i = 0; i < m_Entries.Length; i++)
                        m_TypesOfEntries[i] = m_Entries[i].Type;
                }

                return m_TypesOfEntries;
            }
        }

        private static StealableArtifactsSpawner m_Instance;

        public static StealableArtifactsSpawner Instance
        {
            get
            {
                return m_Instance;
            }
        }

        private static int GetLampPostHue()
        {
            if (0.9 > Utility.RandomDouble())
                return 0;

            return Utility.RandomList(0x455, 0x47E, 0x482, 0x486, 0x48F, 0x4F2, 0x58C, 0x66C);
        }

        public static void Initialize()
        {
            CommandSystem.Register("GenStealArties", AccessLevel.Administrator, new CommandEventHandler(GenStealArties_OnCommand));
            CommandSystem.Register("RemoveStealArties", AccessLevel.Administrator, new CommandEventHandler(RemoveStealArties_OnCommand));
        }

        [Usage("GenStealArties")]
        [Description("Generates the stealable artifacts spawner.")]
        private static void GenStealArties_OnCommand(CommandEventArgs args)
        {
            Mobile from = args.Mobile;

            if (Create())
                from.SendMessage("Stealable artifacts spawner generated.");
            else
                from.SendMessage("Stealable artifacts spawner already present.");
        }

        [Usage("RemoveStealArties")]
        [Description("Removes the stealable artifacts spawner and every not yet stolen stealable artifacts.")]
        private static void RemoveStealArties_OnCommand(CommandEventArgs args)
        {
            Mobile from = args.Mobile;

            if (Remove())
                from.SendMessage("Stealable artifacts spawner removed.");
            else
                from.SendMessage("Stealable artifacts spawner not present.");
        }

        public static bool Create()
        {
            if (m_Instance != null && !m_Instance.Deleted)
                return false;

            m_Instance = new StealableArtifactsSpawner();
            return true;
        }

        public static bool Remove()
        {
            if (m_Instance == null)
                return false;

            m_Instance.Delete();
            m_Instance = null;
            return true;
        }

        public static StealableInstance GetStealableInstance(Item item)
        {
            if (Instance == null)
                return null;

            return (StealableInstance)Instance.m_Table[item];
        }

        public class StealableInstance
        {
            private readonly StealableEntry m_Entry;
            private Item m_Item;
            private DateTime m_NextRespawn;

            public StealableEntry Entry
            {
                get
                {
                    return this.m_Entry;
                }
            }

            public Item Item
            {
                get
                {
                    return this.m_Item;
                }
                set
                {
                    if (this.m_Item != null && value == null)
                    {
                        int delay = Utility.RandomMinMax(this.Entry.MinDelay, this.Entry.MaxDelay);
                        this.NextRespawn = DateTime.Now + TimeSpan.FromMinutes(delay);
                    }

                    if (Instance != null)
                    {
                        if (this.m_Item != null)
                            Instance.m_Table.Remove(this.m_Item);

                        if (value != null)
                            Instance.m_Table[value] = this;
                    }

                    this.m_Item = value;
                }
            }

            public DateTime NextRespawn
            {
                get
                {
                    return this.m_NextRespawn;
                }
                set
                {
                    this.m_NextRespawn = value;
                }
            }

            public StealableInstance(StealableEntry entry) : this(entry, null, DateTime.Now)
            {
            }

            public StealableInstance(StealableEntry entry, Item item, DateTime nextRespawn)
            {
                this.m_Item = item;
                this.m_NextRespawn = nextRespawn;
                this.m_Entry = entry;
            }

            public void CheckRespawn()
            {
                if (this.Item != null && (this.Item.Deleted || this.Item.Movable || this.Item.Parent != null))
                    this.Item = null;

                if (this.Item == null && DateTime.Now >= this.NextRespawn)
                {
                    this.Item = this.Entry.CreateInstance();
                }
            }
        }

        private Timer m_RespawnTimer;
        private StealableInstance[] m_Artifacts;
        private Hashtable m_Table;

        public override string DefaultName
        {
            get
            {
                return "Stealable Artifacts Spawner - Internal";
            }
        }

        private StealableArtifactsSpawner() : base(1)
        {
            this.Movable = false;

            this.m_Artifacts = new StealableInstance[m_Entries.Length];
            this.m_Table = new Hashtable(m_Entries.Length);

            for (int i = 0; i < m_Entries.Length; i++)
            {
                this.m_Artifacts[i] = new StealableInstance(m_Entries[i]);
            }

            this.m_RespawnTimer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromMinutes(15.0), new TimerCallback(CheckRespawn));
        }

        public override void OnDelete()
        {
            base.OnDelete();

            if (this.m_RespawnTimer != null)
            {
                this.m_RespawnTimer.Stop();
                this.m_RespawnTimer = null;
            }

            foreach (StealableInstance si in this.m_Artifacts)
            {
                if (si.Item != null)
                    si.Item.Delete();
            }

            m_Instance = null;
        }

        public void CheckRespawn()
        {
            foreach (StealableInstance si in this.m_Artifacts)
            {
                si.CheckRespawn();
            }
        }

        public StealableArtifactsSpawner(Serial serial) : base(serial)
        {
            m_Instance = this;
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            writer.WriteEncodedInt(0); // version

            writer.WriteEncodedInt(this.m_Artifacts.Length);

            for (int i = 0; i < this.m_Artifacts.Length; i++)
            {
                StealableInstance si = this.m_Artifacts[i];

                writer.Write((Item)si.Item);
                writer.WriteDeltaTime((DateTime)si.NextRespawn);
            }
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version = reader.ReadEncodedInt();

            this.m_Artifacts = new StealableInstance[m_Entries.Length];
            this.m_Table = new Hashtable(m_Entries.Length);

            int length = reader.ReadEncodedInt();

            for (int i = 0; i < length; i++)
            {
                Item item = reader.ReadItem();
                DateTime nextRespawn = reader.ReadDeltaTime();

                if (i < this.m_Artifacts.Length)
                {
                    StealableInstance si = new StealableInstance(m_Entries[i], item, nextRespawn);
                    this.m_Artifacts[i] = si;

                    if (si.Item != null)
                        this.m_Table[si.Item] = si;
                }
            }

            for (int i = length; i < m_Entries.Length; i++)
            {
                this.m_Artifacts[i] = new StealableInstance(m_Entries[i]);
            }

            this.m_RespawnTimer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromMinutes(15.0), new TimerCallback(CheckRespawn));
        }
    }
}